package pong.game;

import java.util.ArrayList;
import java.util.Random;
import java.util.Vector;

import javax.microedition.khronos.opengles.GL10;

import pong.game.artificial_intelligence.BotEasy;
import pong.game.objects.GL_ActiveItem;
import pong.game.objects.GL_Handle;
import pong.game.objects.GL_Object;
import pong.game.objects.GL_Washer;
import pong.game.open_gl.TextureMemoryController;
import pong.game.open_gl.utils.TextureHelper;
import pong.game.user.Party;
import pong.game.user.Player;
import pong.general.R;
import pong.general.SocialPongActivity;
import pong.mathematic.Engine;
import pong.mathematic.Rectangle;
import pong.mathematic.Vector2D;
import pong.mathematic.Vector3D;
import android.content.Context;
import android.opengl.GLES20;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewManager;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.widget.TableRow.LayoutParams;
import android.widget.TextView;

public class Data {

	private static final String TAG = "Data";

	private static final int COUNT_FIRST_GENERATE_TABLO_SPEC_EFFETC = 16;

	private static Data instance = null;

	private static final float GL_COORDS_TRANSFORMER = 50f;

	private Camera camera = new Camera();
	private Player player = null;
	private GL_Object background = null;
	private Context context = null;

	private Party topParty = null;
	private Party bottomParty = null;
	private int topPartyPointsOld = 0;
	private int bottomPartyPointsOld = 0;

	private TextView tablo = null;
	private ArrayList<TextView> tabloSpecEffects = new ArrayList<TextView>();
	private int tabloColor;

	private final TextureMemoryController textureMemoryController = new TextureMemoryController();

	private final Random random = new Random();

	private Vector<GL_Washer> washers = new Vector<GL_Washer>();
	private Vector<GL_Handle> handles = new Vector<GL_Handle>();

	private final Rectangle worldBarrier = new Rectangle();

	/** This is a handle to our texture data. */
	private final TextureDataHandle textures = new TextureDataHandle();

	private Data() {
		clear();
		Log.i(TAG, "Create new data instance");
		camera = new Camera();
		washers = new Vector<GL_Washer>();
		handles = new Vector<GL_Handle>();
		topParty = new Party();
		bottomParty = new Party();
	}

	private TextView createTextView() {
		TextView tabloSpecEffect = new TextView(context);

		tabloSpecEffect.setText("");
		tabloSpecEffect.setTextSize(62);
		tabloSpecEffect.setTextColor(tabloColor);
		// tabloSpecEffect.setl
		tabloSpecEffect.setGravity(Gravity.CENTER);

		LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, Gravity.CENTER);

		((SocialPongActivity) context).addContentView(tabloSpecEffect, params);

		return tabloSpecEffect;
	}

	private void clearTabloSpecEffectsCollection() {
		for (int q = 0; q < tabloSpecEffects.size(); q++) {
			if (tabloSpecEffects.size() == 0)
				continue;

			TextView remove = tabloSpecEffects.get(0);

			ViewManager parent = (ViewManager) remove.getParent();

			if (remove == null || parent == null) {
				Log.e(TAG, "remove tabloSpecEffect == null");
				continue;
			}

			((View) parent).post(new Runnable() {

				public void run() {
					if (tabloSpecEffects.size() == 0)
						return;

					TextView remove = tabloSpecEffects.remove(0);

					if (tabloSpecEffects.size() == 0)
						tabloSpecEffects.clear();

					ViewManager parent = (ViewManager) remove.getParent();

					if (remove == null || parent == null) {
						Log.e(TAG, "remove tabloSpecEffect == null");
						return;
					}

					// Log.i(TAG, "pop tablo " + tabloSpecEffects.size());
					remove.setVisibility(View.GONE);
					remove.clearAnimation();
					remove.clearComposingText();
					remove.clearFocus();
					remove.destroyDrawingCache();
					remove.refreshDrawableState();

					parent.removeView(remove);

					remove = null;
					((View) parent).refreshDrawableState();

					((View) parent).destroyDrawingCache();

					remove = null;
					parent = null;
				}
			});
		}

		tabloSpecEffects.clear();
	}

	private void createTabloSpecEffectsCollection(int size) {

		clearTabloSpecEffectsCollection();

		tabloSpecEffects = new ArrayList<TextView>(size);

		for (int q = 0; q < size; q++)
			tabloSpecEffects.add(createTextView());
	}

	public static void dataReload(Context context) {
		if (instance != null)
			instance.clear();
		instance = new Data();
		instance.context = context;
		instance.topPartyPointsOld = 0;
		instance.bottomPartyPointsOld = 0;
		instance.tabloColor = context.getResources().getColor(R.color.tablo);
		instance.createTabloSpecEffectsCollection(COUNT_FIRST_GENERATE_TABLO_SPEC_EFFETC);

		Party.idCounter = 0;
	}

	public void initSize(float worldHeight, float worldWidth) {
		worldBarrier.setTop(worldHeight / 2f / GL_COORDS_TRANSFORMER);
		worldBarrier.setBottom(worldHeight / -2f / GL_COORDS_TRANSFORMER);
		worldBarrier.setRight(worldWidth / 2f / GL_COORDS_TRANSFORMER);
		worldBarrier.setLeft(worldWidth / -2f / GL_COORDS_TRANSFORMER);

		background = new GL_Object(new Vector3D(0, 0, -0.001f), worldWidth / GL_COORDS_TRANSFORMER, worldHeight
				/ GL_COORDS_TRANSFORMER) {

			@Override
			public boolean isIn(Vector2D point) {
				return getCenter().getY() + height >= point.getY() && getCenter().getY() - height <= point.getY()
						&& getCenter().getX() + width >= point.getX() && getCenter().getX() - width <= point.getX();
			}
		};

		background.setTexture(R.drawable.background, context, false);

		Engine.getInstance().refreshWorld();
	}

	public void loadTextures(Context mActivityContext) {
		textures.background = TextureHelper.loadTexture(mActivityContext, R.drawable.background);
		textures.washer = TextureHelper.loadTexture(mActivityContext, R.drawable.tennis_ball);
		textures.handle = TextureHelper.loadTexture(mActivityContext, R.drawable.red);
	}

	public void clear() {
		washers.clear();
		handles.clear();
		player = null;
		camera = null;
		context = null;
		topParty = null;
		bottomParty = null;

		textureMemoryController.clear();

		clearTabloSpecEffectsCollection();
	}

	public static Data getInstance() {
		if (instance == null) {
			instance = new Data();
		}
		return instance;
	}

	public void sendWifiData() {
		Log.i(TAG, "send wifi data");
	}

	public void initPlayer() {
		player = new Player(getUserName(), new Vector3D(-100500, -100500, 0), 3, 3);
		player.setTexture(R.drawable.blue, context, false);
		player.getImpulse().setTexture(R.drawable.impulse_circle, context, false);
		handles.add(player);

		bottomParty.addPlayer(player);
	}

	public void initBot() {
		BotEasy bot = new BotEasy(getUserName(), new Vector3D(100500, 100500, 0), 3, 3);
		bot.setTexture(R.drawable.blue, context, false);
		bot.getImpulse().setTexture(R.drawable.impulse_circle, context, false);
		handles.add(bot);

		topParty.addPlayer(bot);
	}

	public void initWasher() {

		GL_Washer buffer = new GL_Washer(
				new Vector3D(random.nextFloat() * worldBarrier.getRight() * 2 + worldBarrier.getLeft(),
						random.nextFloat() * worldBarrier.getTop() * 2 + worldBarrier.getBottom(), 0), 1, 1);
		buffer.setDirection(random.nextFloat() * 10 - 5, random.nextFloat() * 10 - 5);
		buffer.setTexture(R.drawable.red, context, false);

		washers.add(buffer);
	}

	public void render(GL10 gl, float[] mModelMatrix, final float[] mMVPMatrix, final float[] mViewMatrix,
			final float[] mProjectionMatrix, final int mProgramHandle, final float[] mLightPosInEyeSpace) {

		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures.background);

		background.render(gl, mModelMatrix, mMVPMatrix, mViewMatrix, mProjectionMatrix, mProgramHandle,
				mLightPosInEyeSpace);

		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures.handle);

		for (int q = 0; q < handles.size(); q++) {
			handles.get(q).render(gl, mModelMatrix, mMVPMatrix, mViewMatrix, mProjectionMatrix, mProgramHandle,
					mLightPosInEyeSpace);
		}

		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures.washer);

		for (int q = 0; q < washers.size(); q++) {
			washers.get(q).render(gl, mModelMatrix, mMVPMatrix, mViewMatrix, mProjectionMatrix, mProgramHandle,
					mLightPosInEyeSpace);
		}

		updateTablo();
	}

	private void updateTablo() {
		if (topParty.getPoints() != topPartyPointsOld || bottomParty.getPoints() != bottomPartyPointsOld) {
			if (tablo == null)
				return;

			Log.i(TAG, "tablo:" + bottomParty.getPoints() + " : " + topParty.getPoints());

			topPartyPointsOld = topParty.getPoints();
			bottomPartyPointsOld = bottomParty.getPoints();

			((SocialPongActivity) context).runOnUiThread(new Runnable() {
				public void run() {
					String str = "" + bottomParty.getPoints() + ":" + topParty.getPoints();
					tablo.setText(str);
					showNewSpecEffectTablo(str);
				}
			});
		}
	}

	private void showNewSpecEffectTablo(String str) {

		for (int q = 0; q < tabloSpecEffects.size(); q++) {
			TextView textView = tabloSpecEffects.get(q);
			if (textView.getAnimation() == null) {
				textView.setText(str);
				textView.startAnimation(getTabloSpecEffectAnimation());
				Log.i(TAG, "aniomation in item number:" + q);
				return;
			}
		}

		TextView textView = createTextView();
		tabloSpecEffects.add(textView);
		textView.setText(str);
		textView.startAnimation(getTabloSpecEffectAnimation());
		Log.i(TAG, "aniomation in item number:" + tabloSpecEffects.size());
	}

	private AnimationSet getTabloSpecEffectAnimation() {
		AnimationSet tabloSpecEffectAnimation = (AnimationSet) AnimationUtils.loadAnimation(context,
				R.anim.tablo_spec_effect);

		return tabloSpecEffectAnimation;
	}

	public void touchItem(int index) {
		// TODO: continue;
	}

	public int countWasherItems() {
		return washers.size();
	}

	public GL_Washer getWasherItem(int index) {
		return washers.get(index);
	}

	public int countHandleItems() {
		return handles.size();
	}

	public GL_Handle getHandleItem(int index) {
		return handles.get(index);
	}

	public int countTouchItems() {
		return 0; // TODO: continue;
	}

	public GL_ActiveItem getTouchItem(int index) {
		return null; // TODO: continue;
	}

	public Rectangle getWorldBarrier() {
		return worldBarrier;
	}

	public Camera getCamera() {
		return camera;
	}

	public Player getPlayer() {
		return player;
	}

	public Party getTopParty() {
		return topParty;
	}

	public Party getBottomParty() {
		return bottomParty;
	}

	public void addPointToParty(Party party) {
		party.addPoints(1);
	}

	public void setTablo(TextView tablo) {
		this.tablo = tablo;
		Log.i(TAG, "set Tablo");
	}

	public TextView getTablo() {
		return tablo;
	}

	public ArrayList<TextView> getTabloSpecEffects() {
		return tabloSpecEffects;
	}

	public String getUserName() {
		return "UserName";
	}

	public TextureMemoryController getTextureMemoryController() {
		return textureMemoryController;
	}

	public class Camera {
		private final Vector3D position = new Vector3D(0, 0, 6);
		private final Vector3D direction = new Vector3D();

		public Vector3D getPosition() {
			return position;
		}

		public Vector3D getDirection() {
			return direction;
		}
	}

	private class TextureDataHandle {
		public int washer;
		public int handle;
		public int background;
	}
}
